package emulator;

import java.util.HashSet;

import keyboard.Keyboard;
import keyboard.Position;

public class ResultCostCalculatorMoveDistance extends ResultCostCalculator {
	final float CODE_VS = 0.5215977f;
	final float[] SCAN_VS = {0f, 0.4029847f, 0.5196843f, 0.8694614f, 1.2672222f};
	final float NEXT_VS = 1.0188424f;
	final float A = 0.59020652f, B = 0.24370553f;
	
	public ResultCostCalculatorMoveDistance(String strategy, int dictSize) {
		super(strategy, dictSize);
		this.costType = "moveDistance";
	}
	
	private float calnFittsLaw(Position startPosition, Position endPosition, Position size) {
		float D = Position.EuclidDist(startPosition, endPosition);
		float W = Math.min(size.r, size.c);
		float cost = A + B * (float)(Math.log(D / W + 1) / Math.log(2f));
		return cost;
	}
	
	public float CalnCost(Keyboard keyboard, Result result) {
		String word = result.GetWord();
		float cost = 0f;
		
		Position lastPosition = keyboard.GetLetterPosition('g');
		for (int i = 0; i < word.length(); i++) {
			keyboard.GroupingStaticKeyboard(result.GetExpression(i));
			HashSet<Character> keysGroup = keyboard.GetKeysGroupOfLetter(word.charAt(i));
			Position centre = keyboard.GetGroupCentrePosition(keysGroup);
			Position size = keyboard.GetGroupSize(keysGroup);
			Position position = Position.getPressPosition(lastPosition, centre, size);
			cost += calnFittsLaw(lastPosition, position, size) + CODE_VS;
			lastPosition = position;
		}
		
		int priority = result.GetPriority();
		int pos = (priority - 1) % 4 + 1;
		int page = (priority - 1) / 4 + 1;
		if (priority <= 4) {
			Position confirmCentre = keyboard.GetSelectorCentrePosition(pos);
			Position confirmSize = keyboard.GetSelectorSize();
			Position confirmPosition = Position.getPressPosition(lastPosition, confirmCentre, confirmSize);
			cost += calnFittsLaw(lastPosition, confirmPosition, confirmSize) + SCAN_VS[pos];
		} else {
			Position nextCentre = keyboard.GetNextCentrePosition();
			Position nextSize = keyboard.GetSelectorSize();
			Position nextPosition = Position.getPressPosition(lastPosition, nextCentre, nextSize);
			Position confirmCentre = keyboard.GetSelectorCentrePosition(pos);
			Position confirmSize = keyboard.GetSelectorSize();
			Position confirmPosition = Position.getPressPosition(nextPosition, confirmCentre, confirmSize);
			cost += calnFittsLaw(lastPosition, nextCentre, nextCentre) + (page - 1) * NEXT_VS;
			cost += calnFittsLaw(nextPosition, confirmPosition, confirmCentre) + SCAN_VS[pos];
		}
		
		return cost;
	}
}
